package com.mdd.front.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mdd.common.core.PageResult;
import com.mdd.common.entity.order.AccountLog;
import com.mdd.common.entity.user.PointsLog;
import com.mdd.common.entity.user.User;
import com.mdd.common.entity.user.UserSignin;
import com.mdd.common.entity.user.UserSigninLog;
import com.mdd.common.enums.AccountChangeEnum;
import com.mdd.common.enums.PointsChangeEnum;
import com.mdd.common.mapper.user.PointsLogMapper;
import com.mdd.common.mapper.user.UserMapper;
import com.mdd.common.mapper.user.UserSigninLogMapper;
import com.mdd.common.mapper.user.UserSigninMapper;
import com.mdd.common.utils.LsConfigUtil;
import com.mdd.common.utils.RedisUtil;
import com.mdd.common.utils.TimeUtil;
import com.mdd.front.service.IUserService;
import com.mdd.front.service.IUserSigninService;
import com.mdd.front.validate.PageParam;
import com.mdd.front.validate.UserPointsUpdateParam;
import com.mdd.front.vo.user.*;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * 用户签到实现类
 * @author panweiliang
 */
@Service
public class UserSigninServiceImpl implements IUserSigninService {

    private final static String SIGNIN_KEY = "signin_date_key_";
    @Resource
    UserSigninMapper userSigninMapper;

    @Resource
    UserSigninLogMapper userSigninLogMapper;

    @Resource
    UserMapper userMapper;

    @Resource
    IUserService userService;

    @Resource
    PointsLogMapper pointsLogMapper;


    /**
     * 用户签到列表
     *
     * @author panweiliang
     * @param pageParam 分页参数
     * @param params 搜索参数
     * @return PageResult<UserSigninListVo>
     */
//    @Override
//    public PageResult<UserSigninListVo> list(PageParam pageParam, Map<String, String> params) {
//        Integer page  = pageParam.getPageNo();
//        Integer limit = pageParam.getPageSize();
//
//        QueryWrapper<UserSignin> queryWrapper = new QueryWrapper<>();
//        queryWrapper.orderByDesc("id");
//
//        userSigninMapper.setSearch(queryWrapper, params, new String[]{
//            "=:userId@user_id:int",
//            "=:days:int",
//            "=:lastSigninTime@last_signin_time:int",
//            "=:signinNums@signin_nums:int",
//        });
//
//        IPage<UserSignin> iPage = userSigninMapper.selectPage(new Page<>(page, limit), queryWrapper);
//
//        List<UserSigninListVo> list = new LinkedList<>();
//        for(UserSignin item : iPage.getRecords()) {
//            UserSigninListVo vo = new UserSigninListVo();
//            BeanUtils.copyProperties(item, vo);
//            vo.setCreateTime(TimeUtil.timestampToDate(item.getCreateTime()));
//            vo.setUpdateTime(TimeUtil.timestampToDate(item.getUpdateTime()));
//            list.add(vo);
//        }
//
//        return PageResult.iPageHandle(iPage.getTotal(), iPage.getCurrent(), iPage.getSize(), list);
//    }


    /**
     * 用户签到新增
     *
     * @author panweiliang
     * @param userId 参数
     */
    @Override
    public Map add(Integer userId) {

        Map<String, Object> result = new HashMap<>();
        User userVo = this.userMapper.selectById(userId);

        String signinDate = (String) RedisUtil.get(SIGNIN_KEY + userId);

        String now = DateUtil.format(new Date(), "yyyy-MM-dd");

        Assert.isTrue(!now.equals(signinDate), "用户今日已签到");

        QueryWrapper<UserSignin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId).isNull("delete_time").last("limit 1");
        UserSignin model =  userSigninMapper.selectOne(queryWrapper);

        Integer days = 1;

        String enable = LsConfigUtil.get("sign-in_points", "enable", "1");
        String changeless = LsConfigUtil.get("sign-in_points", "changeless", "10");
        String rewardRulesJson = LsConfigUtil.get("sign-in_points", "reward_rules_json", "");

        UserPointsUpdateParam userPointsUpdateParam = new UserPointsUpdateParam();
        if (model != null) {
            DateTime yesterday = DateUtil.yesterday();
            Date yesterdayDate = yesterday.toJdkDate();

            List<UserSigninLog> logs = userSigninLogMapper.getBetweenStartAndEnd(DateUtil.beginOfDay(yesterdayDate), DateUtil.endOfDay(yesterdayDate));
            if (logs != null && logs.size() > 0) {
                days = model.getDays();
                days = days != null ? days : 0;
                days = days + 1;

            }

            model.setDays(days);
            model.setLastSigninTime(TimeUtil.timestamp());
            model.setUpdateTime(TimeUtil.timestamp());
            this.userSigninMapper.updateById(model);

        } else {
            model = new UserSignin();
            model.setUserId(userId);
            model.setDays(days);
            model.setLastSigninTime(TimeUtil.timestamp());
            model.setSigninNums(0);
            model.setCreateTime(System.currentTimeMillis() / 1000);
            model.setUpdateTime(System.currentTimeMillis() / 1000);
            userSigninMapper.insert(model);
        }

        BigDecimal reward = new BigDecimal("0");
        if ("1".equals(enable)) {
            reward = new BigDecimal(changeless);
            userPointsUpdateParam.setChangelessPoints(reward);

            JSONArray rewardRulesArray = JSONArray.parseArray(rewardRulesJson);
            if (days <= rewardRulesArray.size()) {

                for (int i = 0 ; i < rewardRulesArray.size(); i++) {
                    JSONObject rewardRuleObj = rewardRulesArray.getJSONObject(i);
                    String date = rewardRuleObj.getString("date");

                    if (date != null && date.equals(days.toString())) {
                        BigDecimal additional = new BigDecimal(rewardRuleObj.getDoubleValue("award"));
                        reward = reward.add(additional);
                        userPointsUpdateParam.setAdditionalPoints(additional);
                        break;
                    }

                }
            }
        }

        BigDecimal userPoints = userVo.getUserPoints();
        userPoints =  userPoints != null ? userPoints : new BigDecimal("0");
        BigDecimal rewardDecimal = new BigDecimal(reward != null ? String.valueOf(reward): "0");

        UserSigninLog userSigninLog = new UserSigninLog();
        userSigninLog.setSigninContent(String.valueOf(1));
        userSigninLog.setSigninType(1);
        userSigninLog.setAddTime(new Date());
        userSigninLog.setPatchTime(null);
        userSigninLog.setUserId(userId);
        userSigninLog.setDays(days);
        userSigninLog.setCreateTime(TimeUtil.timestamp());
        userSigninLog.setUpdateTime(TimeUtil.timestamp());
        this.userSigninLogMapper.insert(userSigninLog);

        userPoints = userPoints.add(rewardDecimal);
        userPointsUpdateParam.setChangePoints(rewardDecimal);
        userPointsUpdateParam.setUserPoints(userPoints);
        userPointsUpdateParam.setRemark("签到增加积分");
        userPointsUpdateParam.setUserId(userId);
        userPointsUpdateParam.setOwnerId(userSigninLog.getId());
        userService.updateUserPoints(userPointsUpdateParam);;


        RedisUtil.set(SIGNIN_KEY + userId, now);

        result.put("days", days);
        result.put("changePoints", rewardDecimal);

        return result;

    }


    @Override
    public PageResult<UserPointsFlowVo> getPointsLog(PageParam pageParam, Integer action, Integer userId) {
        Integer page  = pageParam.getPageNo();
        Integer limit = pageParam.getPageSize();
        action = action != null ? action : -1;
        QueryWrapper<PointsLog> queryWrapper = new QueryWrapper<PointsLog>()
                .select("id,change_type, change_points, update_time")
                .eq("user_id", userId)
                .isNull("delete_time")
                .orderByDesc("update_time");
        if (action.intValue() == PointsChangeEnum.ACTION_INC.getCode()) {
            queryWrapper.in("change_type", PointsChangeEnum.BNW_INC_ADMIN.getCode(), PointsChangeEnum.BNW_INC_ORDER.getCode(), PointsChangeEnum.BNW_INC_ORDER_CANCEL.getCode(), PointsChangeEnum.BNW_INC_SIGIN.getCode());
        } else if (action.intValue() == PointsChangeEnum.ACTION_DEC.getCode()) {
            queryWrapper.in("change_type", PointsChangeEnum.BNW_DEC_ADMIN.getCode(), PointsChangeEnum.BNW_DEC_ORDER.getCode());
        }
        IPage<PointsLog> iPage = pointsLogMapper.selectPage(new Page<>(page, limit), queryWrapper);
        List<UserPointsFlowVo> vos = new LinkedList<>();
        iPage.getRecords().forEach(item -> {
            int changetType = item.getChangeType();
            UserPointsFlowVo userPointsFlowVo = new UserPointsFlowVo();
            userPointsFlowVo.setActionType(getActionType(changetType));
            userPointsFlowVo.setAction(changeTypeMsg(changetType));
            userPointsFlowVo.setAmount(getActionTag(changetType) + item.getChangePoints().toString());
            userPointsFlowVo.setUpdateTime(TimeUtil.timestampToDate(item.getUpdateTime()));
            vos.add(userPointsFlowVo);
        });
        return PageResult.iPageHandle(iPage.getTotal(), iPage.getCurrent(), iPage.getSize(), vos);
    }

    private String changeTypeMsg(int changeType) {
        if (changeType == PointsChangeEnum.BNW_DEC_ADMIN.getCode()) {
            return PointsChangeEnum.BNW_DEC_ADMIN.getMsg();
        } else if (changeType == PointsChangeEnum.BNW_DEC_ORDER.getCode()) {
            return PointsChangeEnum.BNW_DEC_ORDER.getMsg();
        } else if (changeType == PointsChangeEnum.BNW_INC_ADMIN.getCode()) {
            return PointsChangeEnum.BNW_INC_ADMIN.getMsg();
        } else if (changeType == PointsChangeEnum.BNW_INC_ORDER_CANCEL.getCode()) {
            return PointsChangeEnum.BNW_INC_ORDER_CANCEL.getMsg();
        } else if (changeType == PointsChangeEnum.BNW_INC_ORDER.getCode()) {
            return PointsChangeEnum.BNW_INC_ORDER.getMsg();
        } else if (changeType == PointsChangeEnum.BNW_DEC_ORDER_CANCEL.getCode()) {
            return PointsChangeEnum.BNW_DEC_ORDER_CANCEL.getMsg();
        } else {
            return PointsChangeEnum.BNW_INC_SIGIN.getMsg();
        }
    }

    private String getActionTag(int changeType) {
        if (changeType == PointsChangeEnum.BNW_DEC_ADMIN.getCode()) {
            return "-";
        } else if (changeType == PointsChangeEnum.BNW_DEC_ORDER.getCode()) {
            return "-";
        } else if (changeType == PointsChangeEnum.BNW_INC_ADMIN.getCode()) {
            return "+";
        } else if (changeType == PointsChangeEnum.BNW_INC_ORDER.getCode()) {
            return "+";
        } else if (changeType == PointsChangeEnum.BNW_INC_ORDER_CANCEL.getCode()) {
            return "+";
        } else if (changeType == PointsChangeEnum.BNW_DEC_ORDER_CANCEL.getCode()) {
            return "-";
        } else {
            return "+";
        }
    }

    private String getActionType(int changeType) {
        if (changeType == PointsChangeEnum.BNW_DEC_ADMIN.getCode()) {
            return "0";
        } else if (changeType == PointsChangeEnum.BNW_DEC_ORDER.getCode()) {
            return "0";
        } else if (changeType == PointsChangeEnum.BNW_INC_ADMIN.getCode()) {
            return "1";
        } else if (changeType == PointsChangeEnum.BNW_INC_ORDER.getCode()) {
            return "1";
        } else if (changeType == PointsChangeEnum.BNW_INC_ORDER_CANCEL.getCode()) {
            return "1";
        } else {
            return "1";
        }
    }


    @Override
    public UserSiginDetail detail(Integer userId) {
        UserSiginDetail userSiginDetail = new UserSiginDetail();
        QueryWrapper<UserSignin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId).isNull("delete_time").last("limit 1");
        UserSignin model =  userSigninMapper.selectOne(queryWrapper);
        int days = 0;
        if (model != null) {
            days = model.getDays();
            DateTime yesterday = DateUtil.yesterday();
            Date yesterdayDate = yesterday.toJdkDate();

            List<UserSigninLog> logs = userSigninLogMapper.getBetweenStartAndEnd(DateUtil.beginOfDay(yesterdayDate), DateUtil.endOfDay(yesterdayDate));
            if (logs != null && logs.size() == 0) {
                days = 0;
                String signinDate = (String) RedisUtil.get(SIGNIN_KEY + userId);
                String now = DateUtil.format(new Date(), "yyyy-MM-dd");
                if (now.equals(signinDate)) {
                    days = 1;
                }
                model.setDays(days);
                userSigninMapper.updateById(model);
            }
        }
        userSiginDetail.setDays(days);


        User user = this.userMapper.selectById(userId);
        String enable = LsConfigUtil.get("sign-in_points", "enable", "1");
        String rulesJson = LsConfigUtil.get("sign-in_points", "reward_rules_json", "");
        String changelessStr = LsConfigUtil.get("sign-in_points", "changeless", "");
        BigDecimal changeless = new BigDecimal(changelessStr);
        if (!"".equals(rulesJson)) {
            List<UserSiginRule> userSiginRules = JSONArray.parseArray(rulesJson, UserSiginRule.class);
            userSiginDetail.setUserSiginRule(userSiginRules);
            Integer date = 0;
            Map<Integer, UserSiginRule> tempMap = new HashMap<>();
            for(UserSiginRule userSiginRule : userSiginRules) {
                tempMap.put(userSiginRule.getDate(), userSiginRule);
                if (userSiginRule.getDate() > date) {
                    date = userSiginRule.getDate();
                }
            }

            List<UserSiginData> userSiginDatas = new ArrayList<>();
            for (int i = 0; i < date; i++) {
                UserSiginData userSiginData = new UserSiginData();
                Integer day = i + 1;
                userSiginData.setDay(day + "天");
                userSiginData.setSign(day.intValue() <= (userSiginDetail.getDays() != null ? userSiginDetail.getDays().intValue() : 0));
                UserSiginRule temp = tempMap.get(day);
                if (temp != null) {
                    userSiginData.setIntegral(changeless.add(temp.getAward()));
                } else {
                    userSiginData.setIntegral(changeless);
                }
                userSiginDatas.add(userSiginData);
            }
            userSiginDetail.setUserSiginDatas(userSiginDatas);
        }

        userSiginDetail.setRuleDescription(LsConfigUtil.get("sign-in_points", "rule_description", ""));
        if (user != null) {
            userSiginDetail.setUserPoints(user.getUserPoints());
        }
        String signinDate = (String) RedisUtil.get(SIGNIN_KEY + userId);
        String now = DateUtil.format(new Date(), "yyyy-MM-dd");
        userSiginDetail.setTodaySigined(now.equals(signinDate));
        userSiginDetail.setEnable("1".equals(enable));
        return userSiginDetail;
    }
}
